#include "main.h"

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  parse_tree
 *  Description:  parse the expression to the tree root
 * =====================================================================================
 */
int parse_tree (GSList **root, const GString *expr)
{
  gint start_pos = 0;
  gint end = 0;
  gint type = 0;

  g_debug ("[parse_tree]: len = %d\nexpr = (%s)\n", expr->len, expr->str);

  gint index = 0;
  while (start_pos < expr->len) {
    find_tree (expr, start_pos, &end, &type);
//    if (!find_tree (expr, start_pos, &end, &type)) {

    GString *tree_expr = get_tree (expr, start_pos, end);
//    if (!tree_expr)
//      g_critical ("[get_tree]: return null");

      // save tree
    TreeAttr *tree = g_malloc (sizeof (TreeAttr));
    tree->index = index;
    tree->type = type;
    tree->expr = tree_expr;
    tree->head = NULL;
    tree->map = 0;
    tree->point = 0;

    *root = g_slist_append (*root, tree);
    g_debug ("[parse_tree]expr %d: start=%d, end=%d, type=%d\n", index, start_pos, end, type);

//    } else {
//      g_critical ("[parse_tree]: Parse tree error\n");
//      return 1;
//    }

    index++;
    start_pos = end + 1;
  }

  return 0;
}


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  find_tree
 *  Description:  find tree in expression from giving index, the end will be filled with end position
 *  TREE_STATIC means not contain any syntax token.
 *  Args: (expression string, the position to start, returned end position, token)
 *  Return: 0 tree find, 1 no tree found
 * =====================================================================================
 */
void find_tree (const GString *expr, gint start_pos, gint *end, gint *type)
{
  g_return_if_fail (expr);
  g_return_if_fail (start_pos < expr->len);

  gint cur_pos = start_pos;
  if (is_token_start (expr->str[start_pos])) {
    *type = TREE_DYNAMIC;

    GQueue *stack = g_queue_new ();
    g_queue_push_tail (stack, expr->str + start_pos);

    while (1) {
      cur_pos++;

      if (is_token_start (expr->str[cur_pos])) {
        g_queue_push_tail (stack, expr->str + cur_pos);
      } else if (is_token_end (expr->str[cur_pos])) {
        g_queue_pop_tail (stack);
      }

      if (g_queue_is_empty (stack)) {
        *end = cur_pos;
        break;
      }
    }

    g_queue_free (stack);

  } else {
      *type = TREE_STATIC;

    while (1) {
      cur_pos++;

      if (is_token_start (expr->str[cur_pos])) {
        *end = cur_pos-1;
        break;
      }
    }

  }

}


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  get_tree
 *  Description:  get tree at giving position, copy from expression.
 *  Return: newly allocated GString of tree or NULL if get nothing.
 * =====================================================================================
 */
GString *get_tree (const GString *expr, gint start, gint end)
{
  g_return_val_if_fail (expr, NULL);
  g_return_val_if_fail (end >= start, NULL);

  gint i;

  // include start, end point and \0. so, +2
  gint str_len = end - start + 2;

  gchar *str = g_malloc0 (sizeof (char) * str_len);

  for (i = 0; i < str_len; i++) {
    str[i] = expr->str[start + i];
  }
  str[i-1]='\0';

  g_debug ("[get_tree]: len=%d, str=(%s)", str_len, str);

  GString *tree = g_string_new (str);

  g_free (str);

  return tree;
}
